﻿/*
  CTexture2DDDOpenGL.cpp 和 CSkyCubeTextureDDOpenGL.cpp 共同須要的函數
*/


#include <Sys\MATRIX.HPP>
#include <Sys\CSMART_PTR.HPP>
#include <GL\glew.h>    // 包含最新的gl.h,glu.h庫
#include <gl\glut.h>    // 包含OpenGL實用庫


using namespace CxxlMan;
using namespace Cxxl3D;

void cxxlFASTCALL TextureMatrix(const CSmart_Ptr<const C3DMatrix4x4> &TextureMatrix_Arg)
{
  glMatrixMode(GL_TEXTURE);
  if(TextureMatrix_Arg.isNULL() == false)
   glLoadMatrixf( (const float *) (const C3DMatrix4x4*)TextureMatrix_Arg );
  else
  {
    glLoadIdentity();
  }
  //glMatrixMode(GL_MODELVIEW);
}

void cxxlFASTCALL BlendMode(unsigned char Mode)
{
  switch(Mode)
  {
  case 1:      
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    break;
  case 2:      
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
    break;
  default:
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  };
}

// 自動產生貼圖座標
// 參數以 D3D9 的 D3DTSS_TCI 為功能基準
// 0:以頂點在 View 座標系中的 x,y 值作為貼圖的 u,v，頂點的 z 值不使用，內定值(CAMERASPACEPOSITION)
// 1:以頂點在 View 座標系中的 法向量值 作為貼圖的座標值(CAMERASPACENORMAL)
// 2:以 反射向量值 作為貼圖的座標值，其值在 View 座標系中的頂點位置和法向量來計算(CAMERASPACEREFLECTIONVECTOR)
// 3:以頂點在 View 座標系中 法向量的 x,y 值轉換到 [0,1] 區間，作為貼圖的座標值(SPHEREMAP)
// -1:不使用自動產生貼圖座標
bool cxxlFASTCALL AutoTexCoordIndexMode(char Mode)
{
  // 開啟自動產生貼圖座標功能
  glEnable(GL_TEXTURE_GEN_S);
  glEnable(GL_TEXTURE_GEN_T);
  glEnable(GL_TEXTURE_GEN_R);

  bool Ret = false;
  switch(Mode)
  {
  case 0:
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    Ret = true;
    break;
  case 1:
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
    glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
    Ret = true;
    break;
  case 2:
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
    glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
    Ret = true;
    break;
  case 3:
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
    glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
    Ret = true;
    break;
  // case -1:
  //  glDisable(GL_TEXTURE_GEN_S);
  //  glDisable(GL_TEXTURE_GEN_T);
  //  glDisable(GL_TEXTURE_GEN_R);
    //glDisable(GL_TEXTURE_GEN_Q);
  //  return true;
  }

  if(Ret == true)
  {
    // 1*x+0*y+0*z+0*w = x, 貼圖座標 x 軸值等於頂點位置 x 值
	  float fvTexcoordScale_S[] = {1.0f, 0.0f, 0.0f, 0.0f};
 	  glTexGenfv(GL_S, GL_OBJECT_PLANE, fvTexcoordScale_S);

    // 0*x+1*y+0*z+0*w = x, 貼圖座標 y 軸值等於頂點位置 y 值
    float fvTexcoordScale_T[] = {0.0f, 1.0f, 0.0f, 0.0f};
    glTexGenfv(GL_T, GL_OBJECT_PLANE, fvTexcoordScale_T);

    // 0*x+0*y+1*z+0*w = z, 貼圖座標 z 軸值等於頂點位置 z 值
	  float fvTexcoordScale_R[] = {0.0f, 0.0f, 1.0f, 0.0f};
 	  glTexGenfv(GL_R, GL_OBJECT_PLANE, fvTexcoordScale_R);
  }
  else
  {
    glDisable(GL_TEXTURE_GEN_S);
    glDisable(GL_TEXTURE_GEN_T);
    glDisable(GL_TEXTURE_GEN_R);
  }

  return Ret;
}

// 貼圖的 Mipmap 模式 Mode = 0:None(內定) 1:Bilinear 2:Trilinear 3:Anisotropic filter
void cxxlFASTCALL TextureMipmapMode(unsigned char Mode)
{
  // 貼圖被放大時, 取最接近4個點來內插
  glTexParameteri( GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MAG_FILTER, GL_LINEAR );

  switch(Mode)
  {
  case 0:
    // 不使用 mipmap, 取最近 4 個點來平均
    glTexParameteri( GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    // 關閉 anisotrophic filter
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
    break;
  case 1:
    // GL_LINEAR = 貼圖縮小時取 4 個點來平均
    // MIPMAP_NEAREST = 使用最接近大小的圖層
    glTexParameteri( GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
    // 關閉 anisotrophic filter
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
    break;
  case 2:
    // GL_LINEAR = 貼圖縮小時取4個點來平均
    // MIPMAP_LINEAR = 使用最接近大小的兩張圖層, 然後再內插
    glTexParameteri( GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
    // 關閉anisotrophic filter
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
    break;
  case 3:
    // MIPMAP_LINEAR = 使用最接近大小的兩張圖層 , 然後再內插
    glTexParameteri( GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
    // 啟動 anisotrophic filter
    glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f);
  }
}

// 設定貼圖座標模式 Mode = 0:Repeat(內定) 1:Mirror 2:ClampEdge 3:ClampBorder
// Mode 指定為 ClampBorder 時，TextureClampBorderRGBA 指定所用的顏色，內定為 0,0,0,0                       
void TextureAddrMode(unsigned char Mode, unsigned int TextureClampBorderRGBA)
{
  GLint mode;
  float border_color[4];
  const char *_TextureClampBorderRGBA = (const char*)&TextureClampBorderRGBA;

  switch(Mode)
  {
  case 0:
    mode = GL_REPEAT;
    break;
  case 1:
    mode = GL_MIRRORED_REPEAT;
    break;
  case 2:
    mode = GL_CLAMP_TO_EDGE;
    break;
  case 3:
    mode = GL_CLAMP_TO_BORDER;
    border_color[0] = _TextureClampBorderRGBA[0] & 0xff;
    border_color[1] = _TextureClampBorderRGBA[1] & 0xff;
    border_color[2] = _TextureClampBorderRGBA[2] & 0xff;
    border_color[3] = _TextureClampBorderRGBA[3] & 0xff;
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
    break;
  }
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode);
}
